#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os


class BaseConfig(object):

    def __init__(self):
        pass

    def __getitem__(self, key):
        if key in self.__dict__:
            return self.__dict__[key]
        else:
            raise KeyError(key)

    def __setitem__(self, key, value):
        if key in self.__dict__:
            self.__dict__[key] = value
        else:
            raise KeyError(key)

    def __str__(self):
        return str(self.__dict__)

    def __repr__(self):
        return self.__str__()

    def get(self, key, default=None):
        if key in self.__dict__:
            return self.__dict__[key]
        else:
            return default

    def import_settings(self, s):
        self.__dict__.update(s.__dict__)


class AppConfig(BaseConfig):
    config_fields = [
        'test_source_path',
        'test_build_path',
        'test_list_path',
        'bash_lib_path',
        'test_conf_path',
        'test_result_path',
        'test_cache_path',
        'test_run_path',
        'git_password',
        'git_user',
        'test_yaml_path',
    ]

    def __init__(self):
        self.parser = None
        self.subcommand = ""

        # Static path
        self.test_source_path = ""
        self.test_build_path = ""
        self.test_list_path = ""
        self.bash_lib_path = ""
        self.test_conf_path = ""
        self.test_yaml_path = ""

        # Runtime path
        self.test_cache_path = ""
        self.test_run_path = ""
        self.test_result_path = ""

        # Save the parsed test names
        self.test_list = []

        # Other settings
        self.timeout = None
        self.test_interface_shell_map = {
            'check': "install.sh",
            'fetch': "install.sh",
            'install': "install.sh",
            'setup': "run.sh",
            'run': "run.sh",
            'teardown': "run.sh",
            'uninstall': "run.sh",
            'parse': "run.sh",
        }
        self.git_user = ""
        self.git_password = ""

        self.tone_path = ""
        self.is_quiet = True

        self.frame_tool = [
            'bin',
            'core',
            'etc',
            'lib',
            'Makefile',
            'README.md',
            'scripts',
            'tone',
            'tools',
        ]

    def refine_test_list(self):
        """
        To get unique test-suite list by parsing
        test-suite:testconf from test_list

        Return [] test-suite list
        """
        refined = {}
        for index, test in enumerate(self.test_list):
            tmp = test.split(':')
            if tmp[0] not in refined:
                refined[tmp[0]] = index
        order = sorted(refined.items(), key=lambda x: x[1])
        return [k for k, v in order]

    def load_from_yaml(self, fn):
        if os.path.isfile(fn):
            with open(fn, 'r') as stream:
                config = yaml.load(stream, Loader=yaml.loader.SafeLoader)
            for f in self.config_fields:
                if config.get(f) and f in self.__dict__:
                    self[f] = config[f]

    def load_from_env(self):
        """
        Settings will be overwrite by environment variables:
            TONE_WRK_ROOT
            TONE_USER
            TONE_PASS
        """
        tone_wrk_root = os.environ.get('TONE_WRK_ROOT')
        if not tone_wrk_root:
            tone_wrk_root = self.tone_path
        self.test_build_path = os.path.join(tone_wrk_root, 'build')
        self.test_cache_path = os.path.join(tone_wrk_root, 'cache')
        self.test_run_path = os.path.join(tone_wrk_root, 'run')
        self.test_result_path = os.path.join(tone_wrk_root, 'result')

        self.test_source_path = os.path.join(
            self.tone_path, 'tests')
        self.test_conf_path = os.path.join(self.tone_path, 'conf')
        self.test_yaml_path = os.path.join(self.tone_path, 'yaml')

        if 'TONE_USER' in os.environ:
            self.git_user = os.environ.get('TONE_USER')
        if 'TONE_PASS' in os.environ:
            self.git_password = os.environ.get('TONE_PASS')


class JobConfig(BaseConfig):
    def __init__(self):
        self.test_list = []


class TestConfig(BaseConfig):

    test_category = [
        'functional',
        'performance',
        'stress',
    ]

    def __init__(self, name=""):
        self.subcomand = ""

        self.cache_path = ""
        self.build_path = ""
        self.run_path = ""
        self.result_path = ""
        self.result_scenaria_path = ""
        self.result_runtime_path = ""
        self.git_user = ""
        self.git_password = ""

        self.source_path = ""
        self.bash_lib_path = ""
        self._conf_path = ""
        self.yaml_path = ""
        self.tone_path = ""
        self.tone_bin_path = ""

        self.name = name
        self.cleanup_func = None
        self.category = "functional"
        self.env = {}
        self.var = {}
        self.shell_map = {}

        self.stoptime = None
        self.starttime = None
        self.timeout = None
        self.scenaria = []
        self.current_scenaria = None
        self._log_handler = None

        self.script = ""
        self.keep_build = False
        self.is_quiet = True

    @property
    def conf_path(self):
        return self._conf_path

    @conf_path.setter
    def conf_path(self, test_conf_path):
        """
        docstring
        """
        for category in self.test_category:
            conf_path = os.path.join(
                test_conf_path,
                category,
                self.name + '.conf'
            )
            if os.path.isfile(conf_path):
                self._conf_path = conf_path
                self.category = category
                break

    @property
    def log_file_name(self):
        if self.result_path == "":
            return None
        return os.path.join(self.result_path, self.name + '.log')

    def export_script(self, fn):
        with open(fn, 'w') as fh:
            fh.write(self.script)
